#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/syscall_barrier.h>
#include <linux/init.h>

atomic_t	   next_id;
spinlock_t         g_lock = SPIN_LOCK_UNLOCKED;
LIST_HEAD(g_blist);

void __init barrier_init(void) {
	//atomic_t	   next_id;
	//barrier_list_t g_blist;
  /* initialize global variables used by barrier */
    atomic_set(&next_id, 0);
    //    spin_lock_init(&g_lock);
    //    g_blist.list_lock    = SPIN_LOCK_UNLOCKED;
    //g_blist.barrier = NULL;
    //INIT_LIST_HEAD(&(g_blist.list));
}

asmlinkage long sys_barriercreate(int num) {
	if(num < 0)
	{
		return -EINVAL;
	}	
	
	printk(KERN_ALERT "In barriercreate\n");
	
	barrier_data_t *newBarrier=kmalloc(sizeof(barrier_data_t),GFP_KERNEL);
	if(newBarrier==NULL)
	{
		return -ENOMEM;
	}
       
	printk(KERN_ALERT "Allocated mem for new barrier\n");
	
	printk(KERN_ALERT "next_id = %d\n", (int)atomic_read(&next_id));
	
	atomic_set(&newBarrier->ID, atomic_inc_return(&next_id));
	atomic_set(&newBarrier->ref_count, 0);
	atomic_set(&newBarrier->N, num);

	printk(KERN_ALERT "Atomically set new barrier's atomic_t's\n");

	init_waitqueue_head(&newBarrier->wq_head);
	
	printk(KERN_ALERT "init'd the waitqueue\n");
	
	spin_lock_init(&(newBarrier->barrier_lock));

	printk(KERN_ALERT "new barrier's spinlock init'd\n");

	INIT_LIST_HEAD(&(newBarrier->b_list_elem));

	//	barrier_list_t* t_bl = kmalloc(sizeof(barrier_list_t), GFP_KERNEL);

	printk(KERN_ALERT "Allocated mem for barrier list struct\n");
	
	//t_bl->barrier = newBarrier;
	//printk(KERN_ALERT "set the barrier ptr\n");
	//INIT_LIST_HEAD(&t_bl->list);
	//printk(KERN_ALERT "init'd the list head\n");

	//spin_lock(&(g_blist.list_lock));
	//printk(KERN_ALERT "aquired g_blist spinlock\n");
       
	list_add(&(newBarrier->b_list_elem), &g_blist);
	printk(KERN_ALERT "added to t_bl to g_blist\n");
	
	//spin_unlock(&(g_blist.list_lock));
	printk(KERN_ALERT "released lock\n");

	printk(KERN_ALERT "trying to read then return...\n");
	return (long)(atomic_read(&newBarrier->ID));  
	//	return 1;

}
